import sys
parent_dir = "../pygl"
sys.path.append(parent_dir)
import ctypes
import OpenGL.GL as gl
import glm
import imgui
import glfw
from glfw import _GLFWwindow as GLFWwindow
import numpy as np
import pygl
from common import AppWithTrackball, Sphere, AxesHelper, ScreenQuad

class QuadLighting(AppWithTrackball):
    # 初始化着色器，vao vbo等
    def setupVertex(self) -> None:
        gl.glEnable(gl.GL_DEPTH_TEST)
        self.light_program = pygl.ProgramVF("intermediate/shaders/geometry.vs", 
                                      "intermediate/shaders/geometry.fs")
        self.program = pygl.ProgramVF("intermediate/shaders/phong.vs", 
                                      "intermediate/shaders/phong.fs")
        self.background_color = glm.vec4(0.4, 0.4, 0.4, 1.0)
        self.world_axes = AxesHelper(1.5, 5.0)
        self.show_world_axes = True
        self.imgui_window_width = 250
        self.imgui_window_height = 200
        self.light_mode = 4
        self.light = Sphere(0.2)
        self.light_color = glm.vec3(1.0, 1.0, 1.0)
        self.light.position = glm.vec3(1.0, 3.0, 0.0)
        self.sphere = Sphere()
        self.sphere_color = glm.vec3(46.0/255.0, 99.0/255.0, 190.0/255.0)
        self.ambient_color = glm.vec3(1.0, 1.0, 1.0)
        self.Ka = 0.4
        self.Kd = 0.9
        self.Ks = 1.0
        self.shininess = 60.0
        self.framebuffer = pygl.FrameBufferObject(self.width, self.height)
        self.render_texture = pygl.RenderTexture2D(1, gl.GL_RGB16F, self.width, self.height)
        self.render_texture.setFiltering(gl.GL_LINEAR, gl.GL_LINEAR)
        self.framebuffer.attachTexture2D(gl.GL_COLOR_ATTACHMENT0, self.render_texture, 0)
        self.renderbuffer = pygl.RenderBufferObject(gl.GL_DEPTH24_STENCIL8, self.width, self.height)
        self.framebuffer.attachRenderbuffer(gl.GL_DEPTH_STENCIL_ATTACHMENT, gl.GL_RENDERBUFFER, self.renderbuffer)
        if self.framebuffer.isComplete() is not True:
            raise RuntimeError('ERROR::FRAMEBUFFER:: Framebuffer is not complete!')
        self.quad1 = ScreenQuad(self.render_texture)
        self.quad2 = ScreenQuad(self.render_texture, True, 0.5, 1.0, 0.5, 0.5)
        self.quad3 = ScreenQuad(self.render_texture, False, 1.5, 1.0, 2.0, 2.0)
        self.mode = 1

    # 配置imgui界面元素
    def showImGui(self)->None:
        imgui.begin("设置")
        if imgui.button("重置"):
            self.camera.reset(glm.vec3(0.0, 0.0, 3.0), glm.vec3(0.0, 0.0, 0.0), 
                    glm.vec3(0.0, 1.0, 0.0))
        if imgui.radio_button("全屏模式", self.mode == 0):
            self.mode = 0
        if imgui.radio_button("画中画", self.mode == 1):
            self.mode = 1
        if imgui.radio_button("三维屏", self.mode == 2):
            self.mode = 2
        _, self.show_world_axes = imgui.checkbox("显示三维世界坐标轴", 
                                                self.show_world_axes)
        imgui.end()       

    # 渲染图形
    def render(self) -> None:
        self.framebuffer.bind()
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glClearNamedFramebufferfv(self.framebuffer.fbo_id, gl.GL_COLOR, 0, 
                                     glm.vec4(0.9, 0.9, 0.9, 1.0).to_tuple())
        gl.glClearNamedFramebufferfv(self.framebuffer.fbo_id, gl.GL_DEPTH, 0, [1.0]); 
        self.view = self.camera.getViewMatrix()
        self.projection = self.camera.getProjectionMatrix()
        self.renderScene()
        pygl.FrameBufferObject.bindDefault()
        gl.glClearNamedFramebufferfv(0, gl.GL_COLOR, 0, 
                                     self.background_color.to_tuple())
        gl.glClearNamedFramebufferfv(0, gl.GL_DEPTH, 0, [1.0]); 
        if self.mode == 0:
            self.quad1.render(self.view, self.projection)
        elif self.mode == 1:
            self.quad2.render(self.view, self.projection)
            self.renderScene()
        elif self.mode == 2:
            self.quad3.position = glm.vec3(0.0, 0.0, 2.0)
            self.quad3.rotation = glm.vec3(0.0, 0.0, 45.0)
            self.quad3.updateModelMatrix()
            self.quad3.render(self.view, self.projection)
            self.renderScene()

    def renderScene(self) -> None:
        # 代表灯位置的球体
        self.light_program.use()
        self.light.updateModelMatrix()
        self.light_program.setUniformMatrix4fv(0, self.light.model_matrix)
        self.light_program.setUniformMatrix4fv(1, self.view)
        self.light_program.setUniformMatrix4fv(2, self.projection)
        self.light_program.setUniform1i(3, 1)
        self.light_program.setUniform3fv(4, self.light_color)
        self.light.render()
        # 显示光照效果的球体
        self.program.use()
        self.sphere.updateModelMatrix()
        self.program.setUniformMatrix4fv(0, self.sphere.model_matrix)
        self.program.setUniformMatrix4fv(1, self.view)
        self.program.setUniformMatrix4fv(2, self.projection)
        self.program.setUniform3fv(3, self.sphere_color)
        self.program.setUniform3fv(4, self.light_color)
        self.program.setUniform3fv(5, self.light.position)
        self.program.setUniform3fv(6, self.ambient_color)
        self.program.setUniform3fv(7, self.camera.position)
        self.program.setUniform1f(8, self.Ka)
        self.program.setUniform1f(9, self.Kd)
        self.program.setUniform1f(10, self.Ks)
        self.program.setUniform1f(11, self.shininess)
        self.program.setUniform1i(12, self.light_mode)
        self.sphere.render()
        if self.show_world_axes:
            self.world_axes.updateModelMatrix
            self.world_axes.render(self.view, self.projection)

    # 释放资源
    def cleanup(self) -> None:
        self.light.delete()
        self.sphere.delete()
        self.world_axes.delete()
        self.light_program.delete()
        self.program.delete()
        self.framebuffer.delete()
        self.render_texture.delete()
        self.renderbuffer.delete()
        self.quad1.delete()
        self.quad2.delete()
        self.quad3.delete()

    def mouse_move(self, window:GLFWwindow, x:float, y:float)->None:
        if imgui.is_any_item_active():
            return
        super().mouse_move(window, x, y)

    def resize(self, window:GLFWwindow, width:int, height:int)-> None:
        self.width = width
        self.height = height
        gl.glViewport(0, 0, width, height)
        self.camera.aspect = float(width)/height
        self.framebuffer.resize(width, height)
        self.renderbuffer.resize(width, height)
        self.render_texture.resize(width, height)
        self.framebuffer.attachTexture2D(gl.GL_COLOR_ATTACHMENT0, self.render_texture, 0)

if __name__ == "__main__":
    app = QuadLighting(100, 100, 1000, 600, "你好，画中画App！")
    app.run()


